home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Magazine
/
Online
/
httpproxy
/
src
/
net_as225.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-20
|
12KB
|
545 lines
/*(( "Header" */
/*
* $Id: net_as225.c,v 1.5 1996/08/11 22:25:15 mshopf Exp mshopf $
* (c) 1995-96 Matthias Hopf
*
* AS225/INet225/Surfer net protocol stack handler.
*/
/*
* $Log: net_as225.c,v $
* Revision 1.5 1996/08/11 22:25:15 mshopf
* reworked debug messages.
*
* Revision 1.4 1996/07/17 16:42:42 mshopf
* added local hostname fetch.
*
* Revision 1.3 1996/06/03 04:08:19 mshopf
* added error messages.
* added hostname caching.
* added timeouts.
*
* Revision 1.2 1996/04/26 05:14:03 mshopf
* added blocking mode and rudimentary strerror.
* V0.13 alpha 5 fix.
*
* Revision 1.1 1996/04/24 17:41:16 mshopf
* Initial revision
*
* Revision 1.1 1996/04/24 03:20:13 mshopf
* Initial revision
*
*/
/*)) */
/*(( "Includes" */
#include <sys/types.h>
#include <sys/syslog.h>
#include <sys/time.h>
/* Uargl! can't compile without this (include file error...) */
# define SYS_TTYCHARS_H
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <proto/exec.h>
#include <exec/types.h>
#include <ss/socket.h>
#include "net.h"
#include "debug.h"
#define ioctl s_ioctl
#define strcasecmp stricmp
typedef int ioctl_t;
typedef int sock_t;
typedef int len_t;
/*)) */
/*(( "Global variables" */
#define MIN_AS225VERSION 4 /* don't know necessary minimum version, but that's the version of the emulation socket.library... */
#define MAX_HCACHESIZE 32
struct Library *SockBase = NULL;
static fd_set ReadSet;
static fd_set WriteSet;
static fd_set ExceptSet; /* on AS225 we need an additional exception set (see socket() description) */
static sock_t ServerSocket = -1;
static int BlockingMode;
static char *ErrorTxt = NULL; /* extended error information */
struct HostCache { /* no LRU so far... */
char Name [MAXHOSTNAMELEN];
struct in_addr Addr;
};
static struct HostCache HCache [MAX_HCACHESIZE]; /* initialised with 0s */
static struct HostCache *HCacheNext = HCache; /* next cache to be filled */
/*)) */
static const char *as225_strerror (int ErrNo);
/*(( "addcache ()" */
static void addcache (const char *Name, struct in_addr Addr)
{
if (strlen (Name) >= MAXHOSTNAMELEN) /* just to be sure */
return;
debug (D_NET, ("adding cache for '%s'\n", Name));
HCacheNext->Addr = Addr;
strcpy (HCacheNext->Name, Name);
if ( ++HCacheNext >= &HCache [MAX_HCACHESIZE] )
HCacheNext = HCache;
}
/*)) */
/*(( "getaddr ()" */
/* get host address by name, use cache */
static struct in_addr getaddr (const char *Name)
{
struct hostent *HostEnt;
struct in_addr r;
struct HostCache *c;
for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
if (strcmp (c->Name, Name) == 0)
return (c->Addr);
debug (D_NET, ("host '%s' not yet in cache\n", Name));
if ( (r.s_addr = inet_addr ((char *) Name)) +0 == -1)
{
if (! (HostEnt = gethostbyname ((char *) Name)) )
{
ErrorTxt = "Hostname lookup failed";
r.s_addr = (unsigned long) ~0;
return (r);
}
memmove (&r, HostEnt->h_addr, sizeof (r));
addcache (Name, *((struct in_addr *) HostEnt->h_addr));
}
return (r);
}
/*)) */
/*(( "getname ()" */
/* get host name by address, use cache */
/* returns pointer to static buffer */
static const char *getname (struct in_addr Addr)
{
struct hostent *HostEnt;
struct HostCache *c;
for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
if (c->Name [0] && memcmp (&c->Addr, &Addr, sizeof (Addr)) == 0)
return (c->Name);
debug (D_NET, ("hostadr not yet in cache\n"));
if (! (HostEnt = gethostbyaddr ((caddr_t) &Addr, sizeof (struct in_addr), AF_INET)) )
return (inet_ntoa (Addr));
addcache (HostEnt->h_name, Addr);
return (HostEnt->h_name);
}
/*)) */
/*(( "my_syslog ()" */
/* syslog() is not available in AS225 and Surfer... */
static int my_syslog (int Pri, const char *Msg, ...)
{
va_list Args;
char Buffer [512];
va_start (Args, Msg);
vsprintf (Buffer, Msg, Args);
va_end (Args);
return (s_syslog (Pri, Buffer));
}
/*)) */
/*(( "init ()" */
/* Check for socketlibrary and initialise when everything's right */
/* -> BlockMode = FALSE in nonblocking mode */
/* <- TRUE on success, FALSE otherwise */
static int as225_init (int BlockMode)
{
struct servent *ServEnt;
struct hostent *HostEnt;
static char LocalHostName [MAXHOSTNAMELEN];
debug (D_NET, ("AS225 networking module check\n"));
if (SockBase)
return TRUE;
if (! (SockBase = OpenLibrary ("inet:libs/socket.library", MIN_AS225VERSION)))
if (! (SockBase = OpenLibrary ("socket.library", MIN_AS225VERSION)))
return FALSE;
debug (D_NET, ("AS225 networking ok\n"));
if (! (setup_sockets (FD_SETSIZE, &errno)))
{
CloseLibrary (SockBase);
SockBase = NULL;
return FALSE;
}
BlockingMode = BlockMode;
/* get default 'http' protocoll port */
if (! (ServEnt = getservbyname ("http", "tcp")) )
my_syslog (LOG_WARNING, "unknown protocol 'http', using default port %d", DEFAULT_HTTPPORT);
else
{
NetAS225.StdHttpPort = ServEnt->s_port;
if (NetAS225.StdHttpPort != DEFAULT_HTTPPORT)
my_syslog (LOG_WARNING, "protocol 'http' doesn't use default port %d", DEFAULT_HTTPPORT);
}
/* get local hostname */
if (gethostname (LocalHostName, MAXHOSTNAMELEN) < 0)
my_syslog (LOG_ERR, "cannot get local hostname");
else
{
NetAS225.HostName = LocalHostName;
if ( (HostEnt = gethostbyname (LocalHostName)) )
{
strncpy (LocalHostName, HostEnt->h_name, MAXHOSTNAMELEN-1);
LocalHostName [MAXHOSTNAMELEN-1] = '\0';
}
else
my_syslog (LOG_WARNING, "cannot resolve local hostname");
}
return TRUE;
}
/*)) */
/*(( "exit ()" */
/* exit as225 protocol stack handler */
static void as225_exit (void)
{
if (! SockBase)
return;
if (ServerSocket >= 0)
s_close (ServerSocket);
ServerSocket = -1;
cleanup_sockets ();
CloseLibrary (SockBase);
SockBase = NULL;
}
/*)) */
/*(( "select ()" */
/* wait for incoming / outgoing data */
/* -> onNew: called on accepted socket, arguemnts: new fd, calling host's name (static) */
/* -> onTOut: called at least every MIN_TIMEOUT seconds, may be more often */
/* <- TRUE: received Ctrl-C - FALSE: ok or error */
static int as225_select (void (*onNew)(int, const char *), void (*onTOut)(void))
{
struct sockaddr_in PeerIn;
len_t PeerLen = sizeof (PeerIn);
sock_t Peer;
ioctl_t on = 1;
struct timeval OutTime = { MIN_TIMEOUT, 0 };
switch (select (FD_SETSIZE, &ReadSet, &WriteSet, &ExceptSet, &OutTime))
{
case 0:
onTOut ();
return FALSE;
case -1:
if (errno == EINTR)
return TRUE;
syslog (LOG_ERR, "select failed: %s", as225_strerror (errno));
return TRUE; /* and exit... */
}
/* Check server socket for new connections */
if (FD_ISSET (ServerSocket, &ReadSet))
{
if ( (Peer = accept (ServerSocket, (struct sockaddr *) &PeerIn, &PeerLen)) )
{
#ifdef FIOASYNC
if (ioctl (Peer, FIOASYNC, (caddr_t) &on) < 0)
{
my_syslog (LOG_ERR, "ioctl() failed for FIOASYNC: #%d#", errno);
s_close (Peer);
return FALSE;
}
#endif
#ifdef FIONBIO
if (ioctl (Peer, FIONBIO, (caddr_t) &on) < 0)
{
my_syslog (LOG_ERR, "ioctl() failed for FIONBIO: #%d#", errno);
s_close (Peer);
return FALSE;
}
#endif
/* look up hostname here */
onNew ((int) Peer, getname (PeerIn.sin_addr));
}
else
my_syslog (LOG_ERR, "accept() failed: #%d#", errno);
}
return FALSE;
}
/*)) */
/*(( "checkread/write ()" */
static int as225_checkread (int Fd)
{
/* on remote closure of the socket while reading is treated as a exception pending
* socket rather than a readable socket (see select ())*/
return (FD_ISSET (Fd, &ReadSet) || FD_ISSET (Fd, &ExceptSet));
}
static int as225_checkwrite (int Fd)
{
return (FD_ISSET (Fd, &WriteSet));
}
/*)) */
/*(( "read/write ()" */
static int as225_read (int Fd, char *Buffer, int Size)
{
int i;
if ( (i = recv ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
ErrorTxt = "Read failed";
return i;
}
static int as225_write (int Fd, char *Buffer, int Size)
{
int i;
if ( (i = send ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
ErrorTxt = "Write failed";
return i;
}
/*)) */
/*(( "server ()" */
/* open and set up server socket */
static int as225_server (int Port)
{
struct sockaddr_in SockIn;
ioctl_t on = 1;
if (ServerSocket)
s_close (ServerSocket);
if ( (ServerSocket = socket (PF_INET, SOCK_STREAM, 0)) < 0)
{
ErrorTxt = "socket() for serverport failed";
return FALSE;
}
memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
SockIn.sin_family = AF_INET;
SockIn.sin_addr.s_addr = INADDR_ANY;
SockIn.sin_port = htons (Port);
if (bind (ServerSocket, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
{
ErrorTxt = "bind() failed for serverport";
return FALSE;
}
if (! BlockingMode)
{
#ifdef FIOASYNC
if (ioctl (ServerSocket, FIOASYNC, (caddr_t) &on) < 0)
{
ErrorTxt = "ioctl() failed for FIOASYNC";
return FALSE;
}
#endif
#ifdef FIONBIO
if (ioctl (ServerSocket, FIONBIO, (caddr_t) &on) < 0)
{
ErrorTxt = "ioctl() failed for FIONBIO";
return FALSE;
}
#endif
}
if (listen (ServerSocket, 5) < 0)
{
ErrorTxt = "listen() failed";
return FALSE;
}
return TRUE;
}
/*)) */
/*(( "open ()" */
/* open and set up server socket */
/* <- -1: error Fd: otherwise */
static int as225_open (const char *Host, int Port)
{
struct sockaddr_in SockIn;
ioctl_t on = 1;
sock_t Sock;
memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
SockIn.sin_family = AF_INET;
SockIn.sin_port = htons (Port);
if ( (SockIn.sin_addr = getaddr (Host)).s_addr == ~0)
return -1;
if ( (Sock = socket (PF_INET, SOCK_STREAM, 0)) < 0)
{
ErrorTxt = "socket() failed";
return -1;
}
if (! BlockingMode)
{
#ifdef FIOASYNC
if (ioctl (Sock, FIOASYNC, (caddr_t) &on) < 0)
{
ErrorTxt = "ioctl() failed for FIOASYNC";
s_close (Sock);
return -1;
}
#endif
#ifdef FIONBIO
if (ioctl (Sock, FIONBIO, (caddr_t) &on) < 0)
{
ErrorTxt = "ioctl() failed for FIONBIO";
s_close (Sock);
return -1;
}
#endif
}
if (connect (Sock, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
if (errno != EINPROGRESS)
{
ErrorTxt = "connect() failed";
s_close (Sock);
return -1;
}
errno = 0;
return Sock;
}
/*)) */
/*(( "close ()" */
/* open and set up server socket */
static void as225_close (int Fd)
{
s_close ((sock_t) Fd);
}
/*)) */
/*(( "initfd/setfdread/write ()" */
/* <- Server: accept incoming requests */
static void as225_initfd (int Server)
{
FD_ZERO (& ReadSet);
FD_ZERO (& WriteSet);
FD_ZERO (& ExceptSet);
if (Server)
FD_SET (ServerSocket, & ReadSet);
}
static void as225_setfdread (int Fd)
{
FD_SET ((sock_t) Fd, &ReadSet);
FD_SET ((sock_t) Fd, &ExceptSet);
}
static void as225_setfdwrite (int Fd)
{
FD_SET ((sock_t) Fd, &WriteSet);
}
/*)) */
/*(( "strerror ()" */
/* return enhanced error string */
static const char *as225_strerror (int ErrNo)
{
static char Err [128];
if (ErrorTxt)
{
if (ErrNo)
sprintf (Err, "%s: %s", ErrorTxt, strerror (ErrNo));
else
return (ErrorTxt);
ErrorTxt = NULL;
return (Err);
}
else if (ErrNo)
return (strerror (ErrNo));
return ("");
}
/*)) */
/*(( "Method dispatch table" */
netmethods_t NetAS225 = {
"AS225/INet/Surfer",
"unknown",
FD_SETSIZE,
DEFAULT_HTTPPORT,
as225_init,
as225_exit,
as225_select,
as225_checkread,
as225_checkwrite,
as225_read,
as225_write,
as225_server,
as225_open,
as225_close,
as225_initfd,
as225_setfdread,
as225_setfdwrite,
as225_strerror
};
/*)) */